/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 menus.cc                                                  VLC Gtkmmm gui module
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Copyright © 2006-2008 the VideoLAN team

 Authors: David GUGLIELMI <raxxx.fr@gmail.com>
          David LARROQUE <david.larroque@gmail.com>

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 PARTICULAR PURPOSE. See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 Street, Fifth Floor, Boston MA 02110-1301, USA.
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gtkmm/menu.h>
#include <gtkmm/image.h>
#include <gtkmm/imagemenuitem.h>
#include <gtkmm/radiomenuitem.h>
#include <gtkmm/separatormenuitem.h>

#include "dialogs_provider.hh"
#include "input_manager.hh"
#include "gtkmm.hh"
#include "menus.hh"
#include "util/string.hh"

#include <vlc/vlc.h>
#include <vlc_common.h>
#include <vlc_intf_strings.h>
#include <vlc_services_discovery.h>

#include <iomanip>
#include <sstream>

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
enum
{
  ITEM_NORMAL,
  ITEM_CHECK,
  ITEM_RADIO
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static Gtk::RadioMenuItem::Group current_group;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define ACTION(item, function){\
  item->signal_activate ().connect (sigc::ptr_fun (function));}

#define ADD_SEPARATOR {\
  menu->append (*Gtk::manage (new Gtk::SeparatorMenuItem ()));}

#define ADD_IMG_ITEM(imagename, text, accel, modifiertype, function){\
  image_item = new Gtk::ImageMenuItem (*Gtk::manage (new Gtk::Image (\
   Gdk::Pixbuf::create_from_file (Glib::ustring (config_GetDataDir ()) + \
    "/gvlc/"+imagename))),\
                                       q2gm (_(text)),\
                                       true);\
  image_item->add_accelerator ("activate", toplevel->get_accel_group (),\
   accel, modifiertype,Gtk::ACCEL_VISIBLE);\
  ACTION (image_item, function);\
  menu->append (*Gtk::manage (image_item));}

#define ADD_TXT_ITEM(text, accel, modifiertype, function){\
  sub_item = new Gtk::MenuItem (_(text));\
  sub_item->add_accelerator ("activate",\
                             toplevel->get_accel_group (),\
                             accel, modifiertype,\
                             Gtk::ACCEL_VISIBLE);\
  ACTION (image_item, function);\
  menu->append (*Gtk::manage (sub_item));}

#define ADD_CHK_ITEM(text, accel, modifiertype, function){\
  check_item = new Gtk::CheckMenuItem (_(text), false); \
  if (accel) check_item->add_accelerator ("activate",\
                                          toplevel->get_accel_group (),\
                                          accel,\
                                          modifiertype,\
                                          Gtk::ACCEL_VISIBLE);\
  ACTION (image_item, function);\
  menu->append (*Gtk::manage (check_item));}

#define PUSH_VAR(var) varnames.push_back(var); \
  objects.push_back(p_object ? p_object->i_object_id : 0);

#define PUSH_INPUTVAR(var) varnames.push_back(var); \
  objects.push_back(p_input ? p_input->i_object_id : 0);

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuBar*
GVLCMenu::create_menu_bar (Gtk::Window *window, intf_thread_t *p_intf)
{

  Gtk::MenuBar *menu_bar = new Gtk::MenuBar ();
  
  menu_bar->append (*file_menu (window));
  menu_bar->append (*playlist_menu (window, p_intf));
  menu_bar->append (*tools_menu (window, p_intf));
  menu_bar->append (*audio_menu (p_intf));
  menu_bar->append (*video_menu (p_intf));
  menu_bar->append (*playback_menu (window, p_intf));
  menu_bar->append (*help_menu (window));

  return menu_bar;

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::file_menu (Gtk::Window *toplevel)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Media")), true);
  Gtk::Menu *menu = new Gtk::Menu ();

  Gtk::ImageMenuItem *image_item;

  ADD_IMG_ITEM ("vlc_open_file.png", "&Open File...", GDK_O,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_file);
  ADD_IMG_ITEM ("vlc_open_dir.png", "Open D&irectory...", GDK_F,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_dir);
  ADD_IMG_ITEM ("vlc_open_disc.png", "Open &Disc...", GDK_D,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_disc);
  ADD_IMG_ITEM ("vlc_open_network.png", "Open &Network...", GDK_N,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_network);
  ADD_IMG_ITEM ("vlc_capture_device.png", "Open &Capture Device...", GDK_C,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_capture);
  ADD_SEPARATOR;

  ADD_IMG_ITEM ("vlc_stream.png", "&Streaming...", GDK_S,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_streaming);
  ADD_IMG_ITEM ("vlc_convert.png", "Conve&rt / Save...", GDK_R,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_convert);
  ADD_SEPARATOR;

  ADD_IMG_ITEM ("vlc_quit.png", "&Quit", GDK_Q,\
                Gdk::CONTROL_MASK, &DialogsProvider::quit);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::playlist_menu (Gtk::Window *toplevel, intf_thread_t *p_intf)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Playlist")), true);
  Gtk::Menu *menu = new Gtk::Menu ();

  Gtk::ImageMenuItem *image_item;
  Gtk::MenuItem *sub_item;

  menu->append (*Gtk::manage (playlist_sd_submenu (p_intf)));

  ADD_IMG_ITEM ("vlc_playlist.png", "Show Playlist", GDK_L,\
                Gdk::CONTROL_MASK, &DialogsProvider::toggle_playlist);
  ADD_SEPARATOR;

  ADD_IMG_ITEM ("vlc_playlist_open.png", I_PL_LOAD, GDK_X,\
                Gdk::CONTROL_MASK, &DialogsProvider::open_playlist);
  ADD_IMG_ITEM ("vlc_save.png", I_PL_SAVE, GDK_Y,\
                Gdk::CONTROL_MASK, &DialogsProvider::save_playlist);
  ADD_SEPARATOR;

  ADD_TXT_ITEM ("Undock from interface", GDK_U,\
                Gdk::CONTROL_MASK, &DialogsProvider::unlock_playlist);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::tools_menu (Gtk::Window *toplevel, intf_thread_t *p_intf)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Tools")), true);
  Gtk::Menu *menu = new Gtk::Menu ();

  Gtk::ImageMenuItem *image_item;
  Gtk::CheckMenuItem *check_item;
  Gtk::MenuItem *sub_item;

  ADD_IMG_ITEM ("vlc_ext_settings.png", I_MENU_EXT, GDK_E,\
                Gdk::CONTROL_MASK, &DialogsProvider::extented_dialog);
  ADD_SEPARATOR;

  // Interface Sub-menu
  if (1)//with_intf) FIXME
  {
    menu->append (*Gtk::manage (tools_interfaces_submenu (p_intf)));
    ADD_SEPARATOR;
  }

  ADD_CHK_ITEM ("Minimal View...", GDK_H,\
                Gdk::CONTROL_MASK, &DialogsProvider::toggle_minimal_view);
  ADD_CHK_ITEM ("Toggle Fullscreen Interface", GDK_F11,\
                Gdk::LOCK_MASK, &DialogsProvider::toggle_fullscreen);
  ADD_CHK_ITEM ("Advanced controls", GDK_A,\
                Gdk::CONTROL_MASK, &DialogsProvider::toggle_advanced);
  ADD_SEPARATOR;

  ADD_IMG_ITEM ("vlc_messages.png", I_MENU_MSG, GDK_M,\
                Gdk::CONTROL_MASK, &DialogsProvider::message_dialog);
  ADD_IMG_ITEM ("vlc_media_info.png", I_MENU_INFO, GDK_I,\
                Gdk::CONTROL_MASK, &DialogsProvider::media_info_dialog);
  ADD_IMG_ITEM ("vlc_media_info.png", I_MENU_CODECINFO, GDK_J,\
                Gdk::CONTROL_MASK, &DialogsProvider::media_codec_dialog);
  ADD_IMG_ITEM ("vlc_bookmark.png", I_MENU_BOOKMARK, GDK_B,\
                Gdk::CONTROL_MASK, &DialogsProvider::bookmarks_dialog);
#ifdef ENABLE_VLM
  ADD_TXT_ITEM (I_MENU_VLM, GDK_V, Gdk::CONTROL_MASK,\
                &DialogsProvider::vlm_dialog);
#endif
  ADD_SEPARATOR;

  ADD_IMG_ITEM ("vlc_pref.png", "Preferences...", GDK_P,\
                Gdk::CONTROL_MASK, &DialogsProvider::prefs_dialog);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::audio_menu (intf_thread_t *p_intf)
{

 Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Audio")), true);
 Gtk::Menu *menu = new Gtk::Menu ();

  std::vector<int> objects;
  std::vector<const char *> varnames;
  vlc_object_t *p_object; // p_aout
  input_thread_t *p_input;

//TODO Add formated items

  p_input = THEMIM->get_input ();
  if (p_input)
    vlc_object_yield (p_input);
  p_object = (vlc_object_t *) vlc_object_find(p_intf,\
                                              VLC_OBJECT_AOUT,\
                                              FIND_ANYWHERE);
  PUSH_INPUTVAR ("audio-es");
  PUSH_VAR ("audio-device");
  PUSH_VAR ("audio-channels");
  PUSH_VAR ("equalizer");
  PUSH_VAR ("visual");

  if (p_object)
    vlc_object_release (p_object);
  if (p_input)
    vlc_object_release (p_input);

  populate (p_intf, menu, varnames, objects);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::video_menu (intf_thread_t *p_intf)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Video")), true);
  Gtk::Menu *menu = new Gtk::Menu ();

  vlc_object_t *p_object; //p_vout
  input_thread_t *p_input;
  std::vector<int> objects;
  std::vector<const char *> varnames;

  //TODO Add formated items

  p_input = THEMIM->get_input ();
  if (p_input) vlc_object_yield (p_input);
  p_object = (vlc_object_t *) vlc_object_find (p_intf, VLC_OBJECT_VOUT,\
                                               FIND_ANYWHERE );

  PUSH_INPUTVAR ("video-es");
  PUSH_INPUTVAR ("spu-es");
  PUSH_VAR ("fullscreen");
  PUSH_VAR ("zoom");
  PUSH_VAR ("deinterlace");
  PUSH_VAR ("aspect-ratio");
  PUSH_VAR ("crop");
  PUSH_VAR ("video-on-top");
  PUSH_VAR ("directx-wallpaper");
  PUSH_VAR ("video-snapshot");

  if (p_object)
  {
    vlc_object_t *p_dec_obj = (vlc_object_t *)vlc_object_find (p_object,\
                                                     VLC_OBJECT_DECODER,\
                                                     FIND_PARENT );
    if (p_dec_obj)
    {
      vlc_object_t *p_object = p_dec_obj;
      PUSH_VAR ("ffmpeg-pp-q");
      vlc_object_release (p_dec_obj);
    }
  }

  if (p_object) vlc_object_release (p_object);
  if (p_input) vlc_object_release (p_input);

  populate (p_intf, menu, varnames, objects);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::playback_menu (Gtk::Window *toplevel, intf_thread_t *p_intf)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Playback")), true);
  Gtk::Menu *menu = new Gtk::Menu ();

  vlc_object_t *p_object;
  std::vector<int> objects;
  std::vector<const char *> varnames;

  Gtk::ImageMenuItem *image_item;
  ADD_IMG_ITEM ("vlc_gototime.png", I_MENU_GOTOTIME, GDK_T,\
                Gdk::CONTROL_MASK, &DialogsProvider::gototime);

  ADD_SEPARATOR;
  // FIXME add formated items ?
  p_object = (vlc_object_t *)vlc_object_find (p_intf,\
                                              VLC_OBJECT_INPUT,\
                                              FIND_ANYWHERE );
  PUSH_VAR("bookmark");
  PUSH_VAR("title");
  PUSH_VAR("chapter");
  PUSH_VAR("program");
  PUSH_VAR("navigation");
  PUSH_VAR("dvd_menus");

  PUSH_VAR("prev-title");
  PUSH_VAR("next-title");
  PUSH_VAR("prev-chapter");
  PUSH_VAR("next-chapter");
  // FIXME need static stuff ?
  if (p_object)
    vlc_object_release (p_object);

  populate (p_intf, menu, varnames, objects);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::help_menu (Gtk::Window *toplevel)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (q2gm (_("&Help")), true);
  Gtk::Menu *menu = new Gtk::Menu;

  Gtk::ImageMenuItem *image_item;

  ADD_IMG_ITEM ("vlc_help.png", "Help...", GDK_F1,\
                Gdk::LOCK_MASK, &DialogsProvider::help);
#ifdef UPDATE_CHECK
  Gtk::MenuItem *s_item = new Gtk::MenuItem (_("Update"), true);
  ACTION (s_item, &DialogsProvider::update_dialog);
  menu->append (*Gtk::manage (s_item));
#endif
  ADD_SEPARATOR;

  ADD_IMG_ITEM ("vlc_about.png", I_MENU_ABOUT, GDK_U,\
                Gdk::CONTROL_MASK, &DialogsProvider::about);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Submenus
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::playlist_sd_submenu (intf_thread_t *p_intf)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (_(I_PL_SD));
  Gtk::Menu *menu = new Gtk::Menu ();

  char **ppsz_longnames;
  char **ppsz_names = services_discovery_GetServicesNames (p_intf,\
                                                           &ppsz_longnames);
  char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
 
  for (; *ppsz_name; ppsz_name++, ppsz_longname++)
  {
   
    Gtk::CheckMenuItem *check_menu = new Gtk::CheckMenuItem (*ppsz_longname);
    menu->append (*Gtk::manage (check_menu));
   
    if (playlist_IsServicesDiscoveryLoaded (THEPL, *ppsz_name))
      check_menu->set_active (true);

    //FIXME link actions
     
    if (!strcmp (*ppsz_name, "podcast"))
    {
      Gtk::MenuItem *sub_item = new Gtk::MenuItem (_("Configure podcasts..."));
      ACTION (sub_item, &DialogsProvider::podcast_dialog);
      menu->append (*Gtk::manage (sub_item));
    }
     
    free (*ppsz_name);
    free (*ppsz_longname);
  }
  
  free (ppsz_names);
  free (ppsz_longnames);

 item->set_submenu (*Gtk::manage (menu));
 return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Gtk::MenuItem*
GVLCMenu::tools_interfaces_submenu (intf_thread_t *p_intf)
{

  Gtk::MenuItem *item = new Gtk::MenuItem (_("Add Interfaces"));
  Gtk::Menu *menu = new Gtk::Menu ();

  std::vector<int> objects;
  std::vector<const char *> varnames;
  // todo add "switch to XXX"
  varnames.push_back ("intf-add");
  objects.push_back (p_intf->i_object_id);

  populate (p_intf, menu, varnames, objects);

  item->set_submenu (*Gtk::manage (menu));
  return Gtk::manage (item);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Auto-generated menus and items builder
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
GVLCMenu::populate(intf_thread_t *p_intf, Gtk::Menu *menu,\
                   std::vector<const char *> & varnames,\
                   std::vector<int> & objects)
{

// FIXME static entries ?

//  current_group = NULL;
  vlc_object_t *p_object;
  int i;

  for (i = 0; i < (int)objects.size () ; i++)
  {
    if (!varnames[i] || !*varnames[i])
    {
      ADD_SEPARATOR;
      continue;
    }

    if (objects[i] == 0)
    {
      p_object = NULL;
    }
    else
    {
      p_object = (vlc_object_t *)vlc_object_get (p_intf->p_libvlc, objects[i]);
      //p_object = (vlc_object_t *)vlc_object_get (objects[i]);
      if (!p_object)
      {
        msg_Dbg (p_intf, "object %d not found !", objects[i]);
        continue;
      }
    }

    // Ugly specific stuff
    if (strstr (varnames[i], "intf-add"))
      update_item (p_intf, menu, varnames[i], p_object, false);
    else
      update_item (p_intf, menu, varnames[i], p_object, true);
    if (p_object)
      vlc_object_release (p_object);
  }

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool
GVLCMenu::is_menu_empty (const char *psz_var,\
                         vlc_object_t *p_object,\
                         bool b_root = true )
{
  vlc_value_t val, val_list;
  int i_type, i_result, i;

  // Check the type of the object variable
  i_type = var_Type (p_object, psz_var);

  // Check if we want to display the variable
  if (!(i_type & VLC_VAR_HASCHOICE)) return false;

  var_Change (p_object, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL);
  if (val.i_int == 0) return true;

  if ((i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE)
  {
    if (val.i_int == 1 && b_root) return true;
    else return false;
  }

  // Check children variables in case of VLC_VAR_VARIABLE
  if (var_Change (p_object, psz_var, VLC_VAR_GETLIST, &val_list, NULL) < 0)
  {
    return true;
  }

  for (i = 0, i_result = true; i < val_list.p_list->i_count; i++)
  {
    if (!is_menu_empty (val_list.p_list->p_values[i].psz_string,\
                        p_object, false))
    {
      i_result = false;
      break;
    }
  }

  // clean up everything
  var_Change (p_object, psz_var, VLC_VAR_FREELIST, &val_list, NULL);

  return i_result;

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#define TEXT_OR_VAR Glib::ustring (text.psz_string ? text.psz_string : psz_var)
void
GVLCMenu::update_item (intf_thread_t *p_intf, Gtk::Menu *menu,\
                       const char *psz_var, vlc_object_t *p_object,\
                       bool b_submenu)
{
  vlc_value_t val, text;
  int i_type;

  // FIXME static action ?

  if (!p_object)
    return;

  // Check the type of the object variable
  if (!strcmp (psz_var, "audio-es") || !strcmp (psz_var, "video-es"))
    i_type = VLC_VAR_INTEGER | VLC_VAR_HASCHOICE;
  else
    i_type = var_Type (p_object, psz_var);

  switch (i_type & VLC_VAR_TYPE)
  {
    case VLC_VAR_VOID:
    case VLC_VAR_BOOL:
    case VLC_VAR_VARIABLE:
    case VLC_VAR_STRING:
    case VLC_VAR_INTEGER:
    case VLC_VAR_FLOAT:
      break;
    default:
    // Variable doesn't exist or isn't handled
      return;
  }

  // Make sure we want to display the variable
  if (menu->items ().glist () == NULL && is_menu_empty (psz_var, p_object))
    return;

  // Get the descriptive name of the variable
  int i_ret = var_Change (p_object, psz_var, VLC_VAR_GETTEXT, &text, NULL);
  if (i_ret != VLC_SUCCESS)
  {
    text.psz_string = NULL;
  }

  // FIXME another strange action check

  // Some specific stuff
  bool forceDisabled = false;
  if (!strcmp (psz_var, "spu-es"))
  {
    vlc_object_t *p_vout = (vlc_object_t*)(vlc_object_find (p_intf,\
                            VLC_OBJECT_VOUT, FIND_ANYWHERE));
    forceDisabled = (p_vout == NULL);
    if (p_vout)
      vlc_object_release (p_vout);
  }

  if (i_type & VLC_VAR_HASCHOICE)
  {
    // Append choices menu
    if (b_submenu)
    {
      Gtk::MenuItem *item = new Gtk::MenuItem (Glib::ustring (TEXT_OR_VAR));

      Gtk::Menu *submenu = new Gtk::Menu ();
      item->set_sensitive (create_choices_menu (submenu, psz_var,\
                                                p_object, true) == 0);
      
      if (forceDisabled) item->set_sensitive (false);
      item->set_submenu (*Gtk::manage (submenu));
      menu->append (*Gtk::manage (item));
    }
    else
      create_choices_menu (menu, psz_var, p_object, true);

    FREENULL (text.psz_string);
    return;
  }

  switch (i_type & VLC_VAR_TYPE)
  {
    case VLC_VAR_VOID:
      var_Get (p_object, psz_var, &val);
      create_and_connect (menu, psz_var, TEXT_OR_VAR, "", ITEM_NORMAL,
                          p_object->i_object_id, val, i_type);
      break;

    case VLC_VAR_BOOL:
      var_Get (p_object, psz_var, &val);
      val.b_bool = !val.b_bool;
      create_and_connect (menu, psz_var, TEXT_OR_VAR, "", ITEM_CHECK,
                          p_object->i_object_id, val, i_type, !val.b_bool);
      break;
  }
  FREENULL (text.psz_string);

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int
GVLCMenu::create_choices_menu (Gtk::Menu *menu, const char *psz_var,\
                               vlc_object_t *p_object, bool b_root)
{
  vlc_value_t val, val_list, text_list;
  int i_type, i;

  // Check the type of the object variable
  i_type = var_Type (p_object, psz_var);

  // Make sure we want to display the variable
  if (menu->items().glist() == NULL && is_menu_empty (psz_var,\
                                                      p_object,\
                                                      b_root))
    return VLC_EGENERIC;

 switch (i_type & VLC_VAR_TYPE)
 {
   case VLC_VAR_VOID:
   case VLC_VAR_BOOL:
   case VLC_VAR_VARIABLE:
   case VLC_VAR_STRING:
   case VLC_VAR_INTEGER:
   case VLC_VAR_FLOAT:
     break;
   default:
     // Variable doesn't exist or isn't handled
     return VLC_EGENERIC;
 }

 if (var_Change (p_object, psz_var, VLC_VAR_GETLIST, &val_list, &text_list) < 0)
 {
   return VLC_EGENERIC;
 }

#define NORMAL_OR_RADIO i_type & VLC_VAR_ISCOMMAND ? ITEM_NORMAL : ITEM_RADIO
#define NOTCOMMAND !(i_type & VLC_VAR_ISCOMMAND)
#define CURVAL val_list.p_list->p_values[i]
#define CURTEXT text_list.p_list->p_values[i].psz_string

 for (i = 0; i < val_list.p_list->i_count; i++)
 {
   vlc_value_t another_val;
   std::stringstream menutext;
   Gtk::Menu *submenu = new Gtk::Menu ();
   Gtk::MenuItem *item;

   switch (i_type & VLC_VAR_TYPE)
   {
     case VLC_VAR_VARIABLE:
       create_choices_menu (submenu, CURVAL.psz_string, p_object, false );
       item = new Gtk::MenuItem (Glib::ustring (\
        CURTEXT ? CURTEXT : CURVAL.psz_string), true);
       item->set_submenu (*Gtk::manage (submenu));
       menu->append (*Gtk::manage (item));
       break;

     case VLC_VAR_STRING:
       var_Get (p_object, psz_var, &val);
       another_val.psz_string = strdup (CURVAL.psz_string);
       menutext << (CURTEXT ? CURTEXT : another_val.psz_string);
       create_and_connect (menu, psz_var, menutext.str ().c_str (), "",\
                           NORMAL_OR_RADIO, p_object->i_object_id, another_val,\
                           i_type, NOTCOMMAND && val.psz_string && !strcmp (\
                           val.psz_string, CURVAL.psz_string));
       free (val.psz_string);
       break;

     case VLC_VAR_INTEGER:
       var_Get (p_object, psz_var, &val);
       if (CURTEXT) menutext << CURTEXT;
       else menutext << CURVAL.i_int;
       create_and_connect (menu, psz_var, menutext.str ().c_str (), "",\
                           NORMAL_OR_RADIO, p_object->i_object_id, CURVAL,\
                           i_type, NOTCOMMAND && CURVAL.i_int == val.i_int);
       break;

     case VLC_VAR_FLOAT:
       var_Get (p_object, psz_var, &val);
       if (CURTEXT) menutext << CURTEXT;
       else menutext << std::fixed << std::setprecision (2) << CURVAL.f_float;
       create_and_connect (menu, psz_var, menutext.str ().c_str (), "",\
                           NORMAL_OR_RADIO, p_object->i_object_id, CURVAL,\
                           i_type, NOTCOMMAND && CURVAL.f_float == val.f_float);
       break;

     default:
       break;
   }
 }
//FIXME current_group = NULL;

  // clean up everything
  var_Change (p_object, psz_var, VLC_VAR_FREELIST, &val_list, &text_list);

#undef NORMAL_OR_RADIO
#undef NOTCOMMAND
#undef CURVAL
#undef CURTEXT

  return VLC_SUCCESS;

}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void
GVLCMenu::create_and_connect (Gtk::Menu *menu, const char *psz_var,\
                              Glib::ustring text, Glib::ustring help,\
                              int i_item_type, int i_object_id,\
                              vlc_value_t val, int i_val_type, bool checked)
{

//FIXME add connection
//FIXME add help ToolTip

  if (i_item_type == ITEM_CHECK)
  {
    Gtk::CheckMenuItem *item_check = new Gtk::CheckMenuItem (text);
    if (checked) item_check->set_active ();
    item_check->set_sensitive (i_object_id != 0);
    menu->append (*Gtk::manage (item_check));
  }
  else if (i_item_type == ITEM_RADIO)
  {
//    if (!current_group) current_group = 0;
    Gtk::RadioMenuItem *item_radio = new Gtk::RadioMenuItem (current_group,\
                                                             text, false);
    if (checked) item_radio->set_active ();
    item_radio->set_sensitive (i_object_id != 0);
    menu->append (*Gtk::manage (item_radio));
  }
  else
  {
    Gtk::MenuItem *item_normal = new Gtk::MenuItem (text);
    item_normal->set_sensitive (i_object_id != 0);
    menu->append (*Gtk::manage (item_normal));
  }
//FIXME connect action with i_object_id, i_val_type, val, psz_var
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
